package com.specter.mvc.view.json;

import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

/**
 * JSON工具类
 * 
 * 依托Jackson实现 String字符 <-> Java对象 <-> JSON对象 三者间互转
 * 
 * @author Liang.Wang
 * @since 2025-04-01 20:20:20
 */
public class JSON {
    protected static final ObjectMapper mapper = new ObjectMapper();

    // 私有构造器
    private JSON() {
        throw new UnsupportedOperationException("工具类禁止实例化");
    }

    // 初始化配置
    static {
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
    }

    /**
     * 配置ObjectMapper相关属性
     * 
     * <pre>
     * JSON.config(mapper -> {
     *     mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
     *     mapper.setDefaultPropertyInclusion(
     *             JsonInclude.Value.construct(JsonInclude.Include.NON_EMPTY, JsonInclude.Include.ALWAYS));
     * });
     * </pre>
     * 
     * @param configurator 配置器
     */
    public static void config(Consumer<ObjectMapper> configurator) {
        configurator.accept(mapper);
    }

    /**
     * 字符串转成JSON对象：JSONString -> JSONObject/JSONArrays
     * 
     * @param <T>  返回值JSONObject/JSONArrays
     * @param json JSON字符串
     * @return JSONObject/JSONArrays
     */
    @SuppressWarnings("unchecked")
    public static <T> T parse(String json) {
        try {
            JsonNode node = mapper.readTree(json);
            if (node.isObject()) {
                return (T) new JSONObject(node);
            } else if (node.isArray()) {
                return (T) new JSONArrays(node);
            }
            throw new IllegalArgumentException("Unsupported JSON type: " + node.getNodeType());
        } catch (IOException e) {
            throw new RuntimeException("Parse JSON error", e);
        }
    }

    /**
     * JSONString -> JSONObject
     * 
     * @param json JSON字符串
     * @return JSONObject
     */
    public static JSONObject parseObject(String json) {
        return parse(json);
    }

    /**
     * JSONString -> JSONArrays
     * 
     * @param json JSON字符串
     * @return JSONArrays
     */
    public static JSONArrays parseArrays(String json) {
        return parse(json);
    }

    /**
     * 字符串转成Java对象：JSONString -> JavaObject/JavaArrays
     * 
     * @param <T>   返回值类型
     * @param json  JSON字符串
     * @param clazz 目标类类型
     * @return Java对象
     */
    public static Map<?, ?> parseTo(String json) {
        return parseTo(json, java.util.LinkedHashMap.class);
    }

    /**
     * 字符串转成Java对象：JSONString -> JavaObject/JavaArrays
     * 
     * @param <T>   返回值类型
     * @param json  JSON字符串
     * @param clazz 目标类类型
     * @return Java对象
     */
    public static <T> T parseTo(String json, Class<T> clazz) {
        try {
            return mapper.readValue(json, clazz);
        } catch (IOException e) {
            throw new RuntimeException("Parse to Java Object error", e);
        }
    }

    /**
     * JSONString -> JavaObject
     * 
     * @param <T>   返回值类型
     * @param json  JSON字符串
     * @param clazz 目标类类型
     * @return Java对象
     */
    public static <T> T parseToObject(String json, Class<T> clazz) {
        return parseTo(json, clazz);
    }

    /**
     * JSONString -> JavaArrays
     * 
     * @param <T>   返回值类型
     * @param json  JSON字符串
     * @param clazz 目标类类型
     * @return Java对象
     */
    public static <T> List<T> parseToArrays(String json, Class<T> clazz) {
        if (json == null || json.trim().isEmpty()) {
            return Collections.emptyList();
        }
        try {
            JavaType type = mapper.getTypeFactory().constructCollectionType(List.class, clazz);
            return mapper.readValue(json, type);
        } catch (IOException e) {
            throw new RuntimeException("Parse Java List error", e);
        }
    }

    /**
     * Java对象转成JSON对象：JavaObject -> JSONObject/JSONArrays
     * 
     * @param <T> 泛型JSONObject/JSONArrays
     * @param obj Java对象
     * @return JSONObject/JSONArrays
     */
    @SuppressWarnings("unchecked")
    public static <T> T toJSON(Object obj) {
        JsonNode node = mapper.valueToTree(obj);

        if (node.isObject()) {
            return (T) new JSONObject(node);
        }
        if (node.isArray()) {
            return (T) new JSONArrays(node);
        }
        throw new IllegalArgumentException("Unsupported JSON type: " + node.getNodeType());
    }

    /**
     * Java -> JSONObject
     * 
     * @param objs Java对象
     * @return JSONObject
     */
    public static JSONObject toJSONObject(Object objs) {
        return toJSON(objs);
    }

    /**
     * Java -> JSONArrays
     * 
     * @param objs Java对象
     * @return JSONArrays
     */
    public static JSONArrays toJSONArrays(Object objs) {
        return toJSON(objs);
    }

    /**
     * JSON对象转成Java对象：JSON -> JavaObject/JavaArrays
     * 
     * @param json  JSON对象
     * @param clazz 目标类型
     * @param <T>   返回类型
     * @return 转换后的Java对象
     */
    public static <T> T toJava(Object json, Class<T> clazz) {
        if (json instanceof JSONObject jo) {
            return mapper.convertValue(jo.toJsonNode(), clazz);
        }
        if (json instanceof JSONArrays ja) {
            return mapper.convertValue(ja.toJsonNode(),
                    mapper.getTypeFactory().constructCollectionType(List.class, clazz));
        }
        throw new IllegalArgumentException("Unsupported JSON type: " + json.getClass());
    }

    /**
     * JSON -> JavaObject
     * 
     * @param json  JSON对象
     * @param clazz 目标类型
     * @return Java对象
     */
    public static <T> T toJavaObject(JSONObject json, Class<T> clazz) {
        return toJava(json, clazz);
    }

    /**
     * JSON -> JavaArrays
     * 
     * @param json  JSON对象
     * @param clazz 目标类型
     * @return Java对象List列表
     */
    public static <T> List<T> toJavaArrays(JSONArrays json, Class<T> clazz) {
        return mapper.convertValue(json.toJsonNode(),
                mapper.getTypeFactory().constructCollectionType(List.class, clazz));
    }

    /**
     * Java对象/JSON对象转成字符串：JavaObject/JSONObject -> JSONString
     * 
     * @param json Java对象/JSON对象
     * @return 对应字符串
     */
    public static String toJSONString(Object json) {
        try {
            return mapper.writeValueAsString(json);
        } catch (JsonProcessingException e) {
            throw new RuntimeException("Convert to JSON error", e);
        }
    }

}